<!DOCTYPE html>



  


<html class="theme-next muse use-motion" lang="zh-Hans">
<head>
  <meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
<meta name="theme-color" content="#222">









<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />















  
  
  <link href="/blog/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css" />




  
  
  
  

  
    
    
  

  

  

  

  

  
    
    
    <link href="//fonts.googleapis.com/css?family=Lato:300,300italic,400,400italic,700,700italic&subset=latin,latin-ext" rel="stylesheet" type="text/css">
  






<link href="/blog/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css" />

<link href="/blog/css/main.css?v=5.1.2" rel="stylesheet" type="text/css" />


  <meta name="keywords" content="Hexo, NexT" />








  <link rel="shortcut icon" type="image/x-icon" href="/blog/favicon.ico?v=5.1.2" />






<meta property="og:type" content="website">
<meta property="og:title" content="个人博客">
<meta property="og:url" content="http://xiezixi.oschina.io/page/2/index.html">
<meta property="og:site_name" content="个人博客">
<meta property="og:locale" content="zh-Hans">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="个人博客">



<script type="text/javascript" id="hexo.configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/blog/',
    scheme: 'Muse',
    sidebar: {"position":"left","display":"post","offset":12,"offset_float":12,"b2t":false,"scrollpercent":false,"onmobile":false},
    fancybox: true,
    tabs: true,
    motion: true,
    duoshuo: {
      userId: '0',
      author: '博主'
    },
    algolia: {
      applicationID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    }
  };
</script>



  <link rel="canonical" href="http://xiezixi.oschina.io/page/2/"/>





  <title>个人博客</title>
  














</head>

<body itemscope itemtype="http://schema.org/WebPage" lang="zh-Hans">
  
  
    
  

  <div class="container sidebar-position-left 
   page-home 
 ">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-wrapper">
  <div class="site-meta ">
    

    <div class="custom-logo-site-title">
      <a href="/blog/"  class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">个人博客</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
      
        <p class="site-subtitle">曦瓜皮</p>
      
  </div>

  <div class="site-nav-toggle">
    <button>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
    </button>
  </div>
</div>

<nav class="site-nav">
  

  
    <ul id="menu" class="menu">
      
        
        <li class="menu-item menu-item-home">
          <a href="/blog/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-home"></i> <br />
            
            首页
          </a>
        </li>
      
        
        <li class="menu-item menu-item-categories">
          <a href="/blog/categories/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-th"></i> <br />
            
            分类
          </a>
        </li>
      
        
        <li class="menu-item menu-item-archives">
          <a href="/blog/archives/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-archive"></i> <br />
            
            归档
          </a>
        </li>
      

      
    </ul>
  

  
</nav>


 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            
  <section id="posts" class="posts-expand">
    
      

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://xiezixi.oschina.io/blog/2018/06/01/HTML5-SSE/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="曦瓜皮">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/blog/images/avatar.jpg">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="个人博客">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
                
                <a class="post-title-link" href="/blog/2018/06/01/HTML5-SSE/" itemprop="url">HTML5 之 Server-Sent Events™</a></h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2018-06-01T16:51:10+08:00">
                2018-06-01
              </time>
            

            

            
          </span>

          
            <span class="post-category" >
            
              <span class="post-meta-divider">|</span>
            
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              
                <span class="post-meta-item-text">分类于</span>
              
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/blog/categories/HTML5/" itemprop="url" rel="index">
                    <span itemprop="name">HTML5</span>
                  </a>
                </span>

                
                
              
            </span>
          

          
            
          

          
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h2 id="1-什么是-Server-Sent-Events"><a href="#1-什么是-Server-Sent-Events" class="headerlink" title="1. 什么是 Server-Sent Events"></a>1. 什么是 Server-Sent Events</h2><h3 id="1-1-Server-Sent-Events-简介"><a href="#1-1-Server-Sent-Events-简介" class="headerlink" title="1.1. Server-Sent Events 简介"></a>1.1. Server-Sent Events 简介</h3><p>SSE（Server-Sent Event，服务端推送事件）是一种允许服务端向客户端推送新数据的 HTML5 技术。与由客户端每隔几秒从服务端轮询拉取新数据相比，这是一种更优的解决方案。</p>
<h3 id="1-2-SSE-与-WebSocket-相比"><a href="#1-2-SSE-与-WebSocket-相比" class="headerlink" title="1.2. SSE 与 WebSocket 相比"></a>1.2. SSE 与 WebSocket 相比</h3><p>同为浏览器推送技术，相较于 WebSocket 而言，Server-Sent Events （简称SSE）更少被人知晓，具体实践也较少。</p>
<p>原因有两点：</p>
<ul>
<li>WebSocket 比 SSE 更强大，WebSocket 在客户端和服务器之间建立了双向的实时通信。而 SSE 只支持从服务器到客户端的单向实时通信。</li>
<li>WebSocket 在浏览器方面支持更广，IE / Edge 几乎根本不支持 SSE。</li>
</ul>
<p>然而，就第一点而言，与 WebSocket 相比，SSE 也有独特的优势：</p>
<ul>
<li>SSE 的浏览器端实现内置断线重连和消息追踪的功能，WebSocket 也能实现，但是不在协议设计范围内，需要手动处理。</li>
<li>SSE 实现简单，完全复用现有的 HTTP 协议，而 WebSocket 是相对独立于 HTTP 的一套标准，跨平台实现较为复杂。</li>
</ul>
<p>综合而言，相较于 WebSocket，SSE 基于 HTTP 协议单向工作，更加简单，易用。在一些情况下，使用 SSE 反而是更好的选择。</p>
<h3 id="1-3-协议实现"><a href="#1-3-协议实现" class="headerlink" title="1.3. 协议实现"></a>1.3. 协议实现</h3><p>SSE 协议很简单，本质上是一个客户端发起的 HTTP Get 请求，服务器在接到该请求后，返回 200 OK 状态，同时附带以下 Headers</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Content-Type: text/event-stream</span><br><span class="line">Cache-Control: no-cache</span><br><span class="line">Connection: keep-alive</span><br></pre></td></tr></table></figure>
<ul>
<li>SSE 的 MIME Type 规定为 text/event-stream</li>
<li>SSE 肯定不允许缓存</li>
<li>SSE 是一个一直打开的 TCP 连接，所以 Connection 为 Keep-Alive</li>
</ul>
<p>之后，服务器保持连接，在 Body 中持续发送文本流，以实现实时消息推送。</p>
<h3 id="1-4-浏览器兼容性"><a href="#1-4-浏览器兼容性" class="headerlink" title="1.4. 浏览器兼容性"></a>1.4. 浏览器兼容性</h3><p><a href="https://caniuse.com/#search=Server-sent%20events" target="_blank" rel="noopener">Server-Sent Event 浏览器兼容性</a></p>
<h2 id="2-text-event-stream-文本流"><a href="#2-text-event-stream-文本流" class="headerlink" title="2. text/event-stream 文本流"></a>2. text/event-stream 文本流</h2><h3 id="2-1-基础格式"><a href="#2-1-基础格式" class="headerlink" title="2.1 基础格式"></a>2.1 基础格式</h3><p>文本流基础格式如下，以行为单位的，以冒号分割 Field 和 Value，每行结尾为 <code>\n</code>，每行会Trim掉前后空字符，因此 <code>\r\n</code> 也可以。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">field: value\n</span><br></pre></td></tr></table></figure>
<p>注释以冒号打头，格式如下：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">: This is a comment\n</span><br></pre></td></tr></table></figure>
<h3 id="2-2-事件"><a href="#2-2-事件" class="headerlink" title="2.2. 事件"></a>2.2. 事件</h3><p>事件之间用 额外的<code>\n</code> 隔断（即<code>\n\n</code>）， 每个事件既可以为单行，也可为多行。</p>
<h4 id="2-2-1-事件分类"><a href="#2-2-1-事件分类" class="headerlink" title="2.2.1. 事件分类"></a>2.2.1. 事件分类</h4><p>下面所示是两个由单行组成的事件：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">data:  message\n\n</span><br><span class="line">data:  message2\n\n</span><br></pre></td></tr></table></figure>
<p>而这一个是由多行组成的一个事件，更加易读：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">data: &#123;\n</span><br><span class="line">data: &quot;foo&quot;: &quot;bar&quot;,\n</span><br><span class="line">data: &quot;baz&quot;, 555\n</span><br><span class="line">data: &#125;\n\n</span><br></pre></td></tr></table></figure>
<h4 id="2-2-2-事件唯一标示"><a href="#2-2-2-事件唯一标示" class="headerlink" title="2.2.2. 事件唯一标示"></a>2.2.2. 事件唯一标示</h4><p>每一个事件可以指定 ID</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">id: msg1\n</span><br><span class="line">data: message\n\n</span><br></pre></td></tr></table></figure>
<p>浏览器会一直跟踪最近的事件 ID，如果发生了重连，浏览器会把最近接收到的事件 ID 放入 HTTP Header <code>Last-Event-ID</code> 中，作为一种简单的同步机制。</p>
<h4 id="2-2-3-命名事件"><a href="#2-2-3-命名事件" class="headerlink" title="2.2.3. 命名事件"></a>2.2.3. 命名事件</h4><p>除了 ID 唯一标示一个事件之外，也可以通过命名的方式，区分一组类型的事件。默认情况下，事件会被命名为 <code>message</code>。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">event: foo\n</span><br><span class="line">data: a foo event\n\n</span><br><span class="line">data: an unnamed event\n\n</span><br><span class="line">data: a bar event\n</span><br><span class="line">event: bar\n\n</span><br></pre></td></tr></table></figure>
<p>上面的例子实际上是三个事件，第一个事件命名为 “foo”，第二个事件没有命名，第三个事件命名为”bar”。可以看出，在一个事件内部，”event” 可以放在前面，也可以放在末尾。</p>
<h4 id="2-2-4-重连时间"><a href="#2-2-4-重连时间" class="headerlink" title="2.2.4. 重连时间"></a>2.2.4. 重连时间</h4><p>一般情况下，连接中断的时候，客户端会在 3 秒内进行重连，这个时间也可以由服务器来指定</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">retry: 10000\n</span><br></pre></td></tr></table></figure>
<h2 id="3-客户端-API"><a href="#3-客户端-API" class="headerlink" title="3. 客户端 API"></a>3. 客户端 API</h2><h3 id="3-1-检测-SSE-支持"><a href="#3-1-检测-SSE-支持" class="headerlink" title="3.1. 检测 SSE 支持"></a>3.1. 检测 SSE 支持</h3><p>一般可以通过检测 EventSource 对象是否存在来判定当前浏览器是否支持 SSE</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">supportsSSE</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> !!<span class="built_in">window</span>.EventSource;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="3-2-连接事件源"><a href="#3-2-连接事件源" class="headerlink" title="3.2. 连接事件源"></a>3.2. 连接事件源</h3><p>直接创建 EventSource 对象即可，创建完成后，浏览器会及时打开。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">new</span> EventSource(url);</span><br></pre></td></tr></table></figure>
<p>事件源连接后会发送 <code>open</code> 事件，可以用两种方式监听:</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">source.onopen = <span class="function"><span class="keyword">function</span>(<span class="params">event</span>) </span>&#123;</span><br><span class="line">  <span class="comment">// handle open event</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">source.addEventListener(<span class="string">"open"</span>, <span class="function"><span class="keyword">function</span>(<span class="params">event</span>) </span>&#123;</span><br><span class="line">  <span class="comment">// handle open event</span></span><br><span class="line">&#125;, <span class="literal">false</span>);</span><br></pre></td></tr></table></figure>
<h3 id="3-3-接收事件"><a href="#3-3-接收事件" class="headerlink" title="3.3. 接收事件"></a>3.3. 接收事件</h3><p>和上面类似，有两种方式可以接收事件。浏览器会自动把一个消息中的多个分段拼接成一个完整的字符串，因此，可以轻松地在这里使用 JSON 序列化和反序列化处理。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">source.onmessage = <span class="function"><span class="keyword">function</span>(<span class="params">event</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> data = event.data;</span><br><span class="line">  <span class="keyword">var</span> origin = event.origin;</span><br><span class="line">  <span class="keyword">var</span> lastEventId = event.lastEventId;</span><br><span class="line">  <span class="comment">// handle message</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">source.addEventListener(<span class="string">"message"</span>, <span class="function"><span class="keyword">function</span>(<span class="params">event</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> data = event.data;</span><br><span class="line">  <span class="keyword">var</span> origin = event.origin;</span><br><span class="line">  <span class="keyword">var</span> lastEventId = event.lastEventId;</span><br><span class="line">  <span class="comment">// handle message</span></span><br><span class="line">&#125;, <span class="literal">false</span>);</span><br></pre></td></tr></table></figure>
<h3 id="3-4-命名事件"><a href="#3-4-命名事件" class="headerlink" title="3.4. 命名事件"></a>3.4. 命名事件</h3><p>命名事件不会由 <code>message</code> 监听触发，而是使用独立的监听：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">source.addEventListener(<span class="string">"foo"</span>, <span class="function"><span class="keyword">function</span>(<span class="params">event</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> data = event.data;</span><br><span class="line">  <span class="keyword">var</span> origin = event.origin;</span><br><span class="line">  <span class="keyword">var</span> lastEventId = event.lastEventId;</span><br><span class="line">  <span class="comment">// handle message</span></span><br><span class="line">&#125;, <span class="literal">false</span>);</span><br></pre></td></tr></table></figure>
<h3 id="3-5-错误处理"><a href="#3-5-错误处理" class="headerlink" title="3.5. 错误处理"></a>3.5. 错误处理</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">source.onerror = <span class="function"><span class="keyword">function</span>(<span class="params">event</span>) </span>&#123;</span><br><span class="line">  <span class="comment">// handle error event</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">source.addEventListener(<span class="string">"error"</span>, <span class="function"><span class="keyword">function</span>(<span class="params">event</span>) </span>&#123;</span><br><span class="line">  <span class="comment">// handle error event</span></span><br><span class="line">&#125;, <span class="literal">false</span>);</span><br></pre></td></tr></table></figure>
<h3 id="3-6-主动断开连接"><a href="#3-6-主动断开连接" class="headerlink" title="3.6. 主动断开连接"></a>3.6. 主动断开连接</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">source.close();</span><br></pre></td></tr></table></figure>
<h3 id="3-7-连接状态"><a href="#3-7-连接状态" class="headerlink" title="3.7. 连接状态"></a>3.7. 连接状态</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">switch</span> (source.readyState) &#123;</span><br><span class="line">  <span class="keyword">case</span> EventSource.CONNECTING:</span><br><span class="line">    <span class="comment">// do something</span></span><br><span class="line">    <span class="keyword">break</span>;</span><br><span class="line">  <span class="keyword">case</span> EventSource.OPEN:</span><br><span class="line">    <span class="comment">// do something</span></span><br><span class="line">    <span class="keyword">break</span>;</span><br><span class="line">  <span class="keyword">case</span> EventSource.CLOSED:</span><br><span class="line">    <span class="comment">// do something</span></span><br><span class="line">    <span class="keyword">break</span>;</span><br><span class="line">  <span class="keyword">default</span>:</span><br><span class="line">    <span class="comment">// this never happens</span></span><br><span class="line">    <span class="keyword">break</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="4-服务端实现"><a href="#4-服务端实现" class="headerlink" title="4. 服务端实现"></a>4. 服务端实现</h2><p>要在服务器端实现 SSE 必须要注意，SSE 为每个用户保持了一个 TCP 连接，这就意味着Apache 之类的基于 线程/进程 的服务器引擎不适合这个工作。而 Node.js 绝对是最佳选择。</p>
<h2 id="5-简单实例"><a href="#5-简单实例" class="headerlink" title="5. 简单实例"></a>5. 简单实例</h2><h3 id="5-1-服务端-server-js"><a href="#5-1-服务端-server-js" class="headerlink" title="5.1. 服务端 server.js"></a>5.1. 服务端 server.js</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> http = <span class="built_in">require</span>(<span class="string">"http"</span>)</span><br><span class="line"><span class="keyword">var</span> fs = <span class="built_in">require</span>(<span class="string">'fs'</span>)</span><br><span class="line"></span><br><span class="line">http.createServer(<span class="function"><span class="keyword">function</span> (<span class="params">req, res</span>) </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> fileName = <span class="string">"."</span> + req.url;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (fileName === <span class="string">"./stream"</span>) &#123;</span><br><span class="line">        res.writeHead(<span class="number">200</span>, &#123;</span><br><span class="line">            <span class="string">"Content-Type"</span>:<span class="string">"text/event-stream;charset=utf-8"</span>,</span><br><span class="line">            <span class="string">"Cache-Control"</span>:<span class="string">"no-cache"</span>,</span><br><span class="line">            <span class="string">"Connection"</span>:<span class="string">"keep-alive"</span>,</span><br><span class="line">        &#125;);</span><br><span class="line"></span><br><span class="line">        res.write(<span class="string">"retry: 10000\n"</span>);</span><br><span class="line">        res.write(<span class="string">"event: connecttime\n"</span>);</span><br><span class="line">        res.write(<span class="string">": This is a comment\n"</span>);</span><br><span class="line">        res.write(<span class="string">"id: "</span> + (<span class="keyword">new</span> <span class="built_in">Date</span>()).valueOf() + <span class="string">"\n"</span>);</span><br><span class="line">        res.write(<span class="string">"data: "</span> + (<span class="keyword">new</span> <span class="built_in">Date</span>()) + <span class="string">"\n\n"</span>);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">const</span> interval = setInterval(<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">            res.write(<span class="string">"id: "</span> + (<span class="keyword">new</span> <span class="built_in">Date</span>()).valueOf() + <span class="string">"\n"</span>);</span><br><span class="line">            res.write(<span class="string">"data: "</span> + (<span class="keyword">new</span> <span class="built_in">Date</span>()) + <span class="string">"\n\n"</span>);</span><br><span class="line">        &#125;, <span class="number">1000</span>);</span><br><span class="line"></span><br><span class="line">        req.connection.addListener(<span class="string">"close"</span>, <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">            clearInterval(interval);</span><br><span class="line">        &#125;, <span class="literal">false</span>);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        fs.readFile(<span class="string">'./index.html'</span>, <span class="string">'utf8'</span>,<span class="function"><span class="keyword">function</span>(<span class="params">err, html</span>) </span>&#123;</span><br><span class="line">            <span class="keyword">if</span> (err) &#123;</span><br><span class="line">                <span class="built_in">console</span>.error(err);</span><br><span class="line">                <span class="keyword">return</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            res.end(html);</span><br><span class="line">        &#125;)</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;).listen(<span class="number">9999</span>);</span><br></pre></td></tr></table></figure>
<h3 id="5-2-客户端"><a href="#5-2-客户端" class="headerlink" title="5.2. 客户端"></a>5.2. 客户端</h3><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE html&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">"UTF-8"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>SSE<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span> <span class="attr">type</span>=<span class="string">"text/javascript"</span>&gt;</span><span class="undefined"></span></span><br><span class="line"><span class="javascript">    (<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">        <span class="keyword">var</span> source = <span class="keyword">new</span> EventSource(<span class="string">'/stream'</span>)</span></span><br><span class="line"><span class="javascript">        source.onopen = <span class="function"><span class="keyword">function</span>(<span class="params">event</span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">            <span class="built_in">console</span>.log(event);</span></span><br><span class="line"><span class="undefined">        &#125;</span></span><br><span class="line"><span class="undefined"></span></span><br><span class="line"><span class="javascript">        source.onmessage = <span class="function"><span class="keyword">function</span>(<span class="params">event</span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">            <span class="built_in">console</span>.log(event);</span></span><br><span class="line"><span class="javascript">            <span class="built_in">document</span>.body.innerHTML = event.data;</span></span><br><span class="line"><span class="undefined">        &#125;</span></span><br><span class="line"><span class="undefined"></span></span><br><span class="line"><span class="javascript">        source.onerror = <span class="function"><span class="keyword">function</span>(<span class="params">error</span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">            <span class="built_in">console</span>.log(error)</span></span><br><span class="line"><span class="undefined">        &#125;</span></span><br><span class="line"><span class="undefined">    &#125;)()</span></span><br><span class="line"><span class="undefined"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h3 id="5-3-请求查看"><a href="#5-3-请求查看" class="headerlink" title="5.3. 请求查看"></a>5.3. 请求查看</h3><p><img src="http://xiezixi.oschina.io/blog/images/sse2.png" alt="请求查看2"></p>
<p><img src="http://xiezixi.oschina.io/blog/images/sse1.png" alt="请求查看1"></p>

          
        
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </div>
  
  
  
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://xiezixi.oschina.io/blog/2018/06/01/HTML5-WebStorage/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="曦瓜皮">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/blog/images/avatar.jpg">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="个人博客">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
                
                <a class="post-title-link" href="/blog/2018/06/01/HTML5-WebStorage/" itemprop="url">HTML5 之 WebStorage™</a></h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2018-06-01T16:45:17+08:00">
                2018-06-01
              </time>
            

            

            
          </span>

          
            <span class="post-category" >
            
              <span class="post-meta-divider">|</span>
            
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              
                <span class="post-meta-item-text">分类于</span>
              
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/blog/categories/HTML5/" itemprop="url" rel="index">
                    <span itemprop="name">HTML5</span>
                  </a>
                </span>

                
                
              
            </span>
          

          
            
          

          
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h2 id="1-HTML5-之前的存储方式"><a href="#1-HTML5-之前的存储方式" class="headerlink" title="1. HTML5 之前的存储方式"></a>1. HTML5 之前的存储方式</h2><h3 id="1-1-Cookies"><a href="#1-1-Cookies" class="headerlink" title="1.1.Cookies"></a>1.1.Cookies</h3><p>作为一个前端和 Cookie 打交道的次数肯定不会少了，Cookie 算是比较古老的技术了。1993 年，网景公司雇员 Lou Montulli 为了让用户在访问某网站时，进一步提高访问速度，同时也为了进一步实现个人化网络，发明了今天广泛使用的 Cookie。</p>
<h4 id="1-1-1-Cookie-的特点"><a href="#1-1-1-Cookie-的特点" class="headerlink" title="1.1.1. Cookie 的特点"></a>1.1.1. Cookie 的特点</h4><ol>
<li>Cookie 的大小受限制，Cookie 大小被限制在4KB，不能接受像大文件或邮件那样的大数据；</li>
<li>只要有请求涉及 Cookie，Cookie 就要在服务器和浏览器之间来回传送。而且 Cookie 数据始终在同源的 HTTP 请求中携带（即使不需要），这也是 Cookie 不能太大的重要原因。正统的 Cookie 分发是通过扩展 HTTP 协议来实现的，服务器通过在 HTTP 的响应头中加上一行特殊的指示以提示浏览器按照指示生成相应的 Cookie；</li>
<li>Cookie 的内容主要包括：名字，值，过期时间，路径和域。路径与域一起构成 Cookie 的作用范围。若不设置过期时间，则表示这个 Cookie 的生命期为浏览器会话期间，关闭浏览器窗口，Cookie 就消失。这种生命期为浏览器会话期的 Cookie 被称为会话 Cookie。会话 Cookie 一般不存储在硬盘上而是保存在内存里，当然这种行为并不是规范规定的。若设置了过期时间，浏览器就会把 Cookie 保存到硬盘上，关闭后再次打开浏览器，这些 Cookie 仍然有效直到超过设定的过期时间。存储在硬盘上的 Cookie 可以在不同的浏览器进程间共享，比如两个IE窗口。而对于保存在内存里的 Cookie，不同的浏览器有不同的处理方式。</li>
</ol>
<h4 id="1-1-2-document-cookie-的属性"><a href="#1-1-2-document-cookie-的属性" class="headerlink" title="1.1.2. document.cookie 的属性"></a>1.1.2. document.cookie 的属性</h4><p><strong> expires属性 </strong></p>
<blockquote>
<p>指定了 Cookie 的生存期，默认情况下 Cookie 是暂时存在的，他们存储的值只在浏览器会话期间存在，当用户推出浏览器后这些值也会丢失，如果想让 Cookie 存在一段时间，就要为 expires 属性设置为未来的一个过期日期。现在已经被 max-age 属性所取代，max-age 用秒来设置 Cookie 的生存期。</p>
</blockquote>
<p><strong> path属性 </strong></p>
<blockquote>
<p>它指定与 Cookie 关联在一起的网页。在默认的情况下 Cookie 会与创建它的网页，该网页处于同一目录下的网页以及与这个网页所在目录下的子目录下的网页关联。</p>
</blockquote>
<p><strong> domain属性 </strong></p>
<blockquote>
<p>domain 属性可以使多个 web 服务器共享 cookie。domain 属性的默认值是创建 cookie 的网页所在服务器的主机名。不能将一个 cookie 的域设置成服务器所在的域之外的域。例如让位于<code>order.damonare.cn</code>的服务器能够读取<code>catalog.damonare.cn</code>设置的 cookie 值。如果<code>catalog.damonare.cn</code>的页面创建的 cookie 把自己的 path 属性设置为<code>/</code>，把 domain 属性设置成<code>.damonare.cn</code>，那么所有位于<code>catalog.damonare.cn</code>的网页和所有位于<code>orlders.damonare.cn</code>的网页，以及位于<code>damonare.cn</code>域的其他服务器上的网页都可以访问这个  cookie。</p>
</blockquote>
<p><strong> secure属性 </strong></p>
<blockquote>
<p>它是一个布尔值，指定在网络上如何传输 cookie，默认是不安全的，通过一个普通的 http 连接传输</p>
</blockquote>
<h4 id="1-1-3-优秀开源框架"><a href="#1-1-3-优秀开源框架" class="headerlink" title="1.1.3. 优秀开源框架"></a>1.1.3. 优秀开源框架</h4><p><a href="https://github.com/js-cookie/js-cookie" target="_blank" rel="noopener">js-cookie</a>，<a href="https://github.com/carhartl/jquery-cookie" target="_blank" rel="noopener">jquery-cookie</a>。</p>
<h3 id="1-2-UserData"><a href="#1-2-UserData" class="headerlink" title="1.2. UserData"></a>1.2. UserData</h3><p>仅 IE 支持，容量为 64KB。</p>
<h3 id="1-3-Flash"><a href="#1-3-Flash" class="headerlink" title="1.3. Flash"></a>1.3. Flash</h3><p>100KB，非 HTML 原生，需要插件支持。</p>
<h3 id="1-4-Google-Gears-SQLite"><a href="#1-4-Google-Gears-SQLite" class="headerlink" title="1.4. Google Gears SQLite"></a>1.4. Google Gears SQLite</h3><p>需要插件支持，容量无限制。</p>
<h2 id="2-localStorage"><a href="#2-localStorage" class="headerlink" title="2. localStorage"></a>2. localStorage</h2><h3 id="2-1-什么是-localStorage"><a href="#2-1-什么是-localStorage" class="headerlink" title="2.1. 什么是 localStorage"></a>2.1. 什么是 localStorage</h3><p>localStorage 为标准的键值对（Key-Value,简称KV）数据类型，简单但也易扩展，只要以某种编码方式把想要存储进 localStorage 的对象给转化成字符串，就能轻松支持。举点例子：把对象转换成 json 字符串，就能让存储对象了；把图片转换成 DataUrl（base64），就可以存储图片了。另外对于键值对数据类型来说，“键是唯一的”这个特性也是相当重要的，重复以同一个键来赋值的话，会覆盖上次的值。底层数据接口是 sqlite，按域名将数据分别保存到对应数据库文件里。它能保存更大的数据（IE8 上是 10MB，Chrome 是5 MB），同时保存的数据不会再发送给服务器，避免带宽浪费。</p>
<h3 id="2-2-localStorage-特点"><a href="#2-2-localStorage-特点" class="headerlink" title="2.2. localStorage 特点"></a>2.2. localStorage 特点</h3><p>localStorage 理论上来说是永久有效的，即不主动清空的话就不会消失，即使保存的数据超出了浏览器所规定的大小，也不会把旧数据清空而只会报错。但需要注意的是，在移动设备上的浏览器或各 Native App 用到的 WebView 里，localStorage 都是不可靠的，可能会因为各种原因（比如说退出 App、网络切换、内存不足等原因）被清空。</p>
<p>localStorage 原生是不支持设置过期时间的，想要设置的话，就只能自己来封装一层逻辑来实现：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">set</span>(<span class="params">key, value</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> curTime = <span class="keyword">new</span> <span class="built_in">Date</span>().getTime();<span class="comment">//获取当前时间</span></span><br><span class="line">    localStorage.setItem(key, <span class="built_in">JSON</span>.stringify(&#123;<span class="attr">val</span>: value, <span class="attr">time</span>: curTime&#125;));<span class="comment">//转换成json字符串序列</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">get</span>(<span class="params">key, exp</span>)//<span class="title">exp</span>是设置的过期时间</span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">var</span> val = localStorage.getItem(key);<span class="comment">//获取存储的元素</span></span><br><span class="line">    <span class="keyword">var</span> dataObj = <span class="built_in">JSON</span>.parse(val);<span class="comment">//解析出json对象</span></span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">new</span> <span class="built_in">Date</span>().getTime() - dataObj.time &gt; exp)<span class="comment">//如果当前时间-减去存储的元素在创建时候设置的时间 &gt; 过期时间</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">"expires"</span>);<span class="comment">//提示过期</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">"val="</span> + dataObj.val);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="2-3-localStorage-的属性方法"><a href="#2-3-localStorage-的属性方法" class="headerlink" title="2.3. localStorage 的属性方法"></a>2.3. localStorage 的属性方法</h3><table>
<thead>
<tr>
<th>属性方法</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>localStorage.length</code></td>
<td>获得 storage 中的个数</td>
</tr>
<tr>
<td><code>localStorage.key(n)</code></td>
<td>获得 storage 中第 n 个元素对的键值（第一个元素是 0）</td>
</tr>
<tr>
<td><code>localStorage.getItem(key)</code></td>
<td>获取键值 key 对应的值</td>
</tr>
<tr>
<td><code>localStorage.setItem(key, value)</code></td>
<td>添加数据，键值为 key，值为 value</td>
</tr>
<tr>
<td><code>localStorage.removeItem(key)</code></td>
<td>移除键值为 key 的数据</td>
</tr>
<tr>
<td><code>localStorage.clear()</code></td>
<td>清除所有数据</td>
</tr>
</tbody>
</table>
<h3 id="2-4-localStorage-的缺点"><a href="#2-4-localStorage-的缺点" class="headerlink" title="2.4. localStorage 的缺点"></a>2.4. localStorage 的缺点</h3><ul>
<li>localStorage 大小有限制，各个浏览器不一致</li>
<li>localStorage 在隐私模式下不可读取</li>
<li>localStorage 本质是在读写文件，数据多的话会比较卡</li>
<li>localStorage 不能被爬虫爬取，不要用它完全取代 URL 传参</li>
<li>WebStorage 固然简单实用，但是数据的明文存储实在是硬伤</li>
</ul>
<h3 id="2-5-兼容性情况"><a href="#2-5-兼容性情况" class="headerlink" title="2.5. 兼容性情况"></a>2.5. 兼容性情况</h3><p><a href="https://caniuse.com/#search=webstorage" target="_blank" rel="noopener">webStroage兼容性情况</a></p>
<h2 id="3-sessionStorage"><a href="#3-sessionStorage" class="headerlink" title="3. sessionStorage"></a>3. sessionStorage</h2><h3 id="3-1-sessionStorage-的特点"><a href="#3-1-sessionStorage-的特点" class="headerlink" title="3.1. sessionStorage 的特点"></a>3.1. sessionStorage 的特点</h3><p>和服务器端使用的 session 类似，是一种会话级别的缓存，关闭浏览器会数据会被清除。不过有点特别的是它的作用域是窗口级别的，也就是说不同窗口间的 sessionStorage 数据不能共享的。</p>
<h3 id="3-2-sessionStorage-的属性方法"><a href="#3-2-sessionStorage-的属性方法" class="headerlink" title="3.2. sessionStorage 的属性方法"></a>3.2. sessionStorage 的属性方法</h3><p>使用方法（和 localStorage 完全相同）：</p>
<table>
<thead>
<tr>
<th>属性方法</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>sessionStorage.length</code></td>
<td>获得 storage 中的个数</td>
</tr>
<tr>
<td><code>sessionStorage.key(n)</code></td>
<td>获得 storage 中第 n 个元素对的键值（第一个元素是 0）</td>
</tr>
<tr>
<td><code>sessionStorage.getItem(key)</code></td>
<td>获取键值 key 对应的值</td>
</tr>
<tr>
<td><code>sessionStorage.setItem(key, value)</code></td>
<td>添加数据，键值为 key，值为 value</td>
</tr>
<tr>
<td><code>sessionStorage.removeItem(key)</code></td>
<td>移除键值为 key 的数据</td>
</tr>
<tr>
<td><code>sessionStorage.clear()</code></td>
<td>清除所有数据</td>
</tr>
</tbody>
</table>
<h2 id="4-webStorage-事件监测"><a href="#4-webStorage-事件监测" class="headerlink" title="4. webStorage 事件监测"></a>4. webStorage 事件监测</h2><p>在HTML5中，可以通 过 window 对象的 storage 事件进行监听。当存储的 storage 数据发生变化时都会触发它,也就是说当前页面的 storage 改变的时候,触发这个事件也会触发调用所有同域下其他窗口的 storage 事件。但要注意：该事件不会在导致数据变化的当前页面触发。</p>
<p><strong>使用<code>addEventListener</code>进行监听</strong></p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">window</span>.addEventListener(<span class="string">'storage'</span>,<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    <span class="comment">//当sessionStorage或localStorage中的值发生变动时所要执行的处理</span></span><br><span class="line">&#125;,<span class="literal">false</span>);</span><br></pre></td></tr></table></figure>
<p>在事件处理函数中，触发事件的事件对象（event 参数值）有以下属性：</p>
<table>
<thead>
<tr>
<th>属性方法</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>event.key</code></td>
<td>被修改的数据键值</td>
</tr>
<tr>
<td><code>event.oldValue</code></td>
<td>被修改前的值</td>
</tr>
<tr>
<td><code>event.newValue</code></td>
<td>被修改后的值</td>
</tr>
<tr>
<td><code>event.url</code></td>
<td>页面URL地址</td>
</tr>
<tr>
<td><code>event.storageArea</code></td>
<td>变动的 sessionStorage 对象或 localStorage对象</td>
</tr>
<tr>
<td><code>sessionStorage.clear()</code></td>
<td>清除所有数据</td>
</tr>
</tbody>
</table>
<h2 id="5-webStorage-和-cookie-的区别"><a href="#5-webStorage-和-cookie-的区别" class="headerlink" title="5. webStorage 和 cookie 的区别"></a>5. webStorage 和 cookie 的区别</h2><p><strong>localStorage 和 sessionStorage 的区别主要是在于其生存期</strong></p>
<ul>
<li><p>sessionStorage 用于本地存储一个会话（session）中的数据，这些数据只有在同一个会话中的页面才能访问并且当会话结束后数据也随之销毁。因此sessionStorage不是一种持久化的本地存储，仅仅是会话级别的存储。当用户关闭浏览器窗口后，数据立马会被删除。</p>
</li>
<li><p>localStorage 用于持久化的本地存储，除非主动删除数据，否则数据是永远不会过期的。第二天、第二周或下一年之后，数据依然可用。</p>
</li>
</ul>
<p><strong>webStorage 和 cookie 的区别</strong></p>
<ul>
<li>WebStorage（localStorage 和 sessionStorage）的概念和 cookie 相似，区别是它是为了更大容量存储设计的。Cookie 的大小是受限的，并且每次你请求一个新的页面的时候 Cookie 都会被发送过去，这样无形中浪费了带宽，另外cookie还需要指定作用域，不可以跨域调用。</li>
<li>除此之外，WebStorage 拥有 setItem, getItem, removeItem, clear等方法，不像 cookie 需要前端开发者自己封装 setCookie，getCookie。</li>
<li>但是 Cookie 也是不可以或缺的：Cookie 的作用是与服务器进行交互，作为 HTTP 规范的一部分而存在 ，而 WebStorage 仅仅是为了在本地“存储”数据而生。</li>
</ul>
<h2 id="6-网页皮肤实例"><a href="#6-网页皮肤实例" class="headerlink" title="6. 网页皮肤实例"></a>6. 网页皮肤实例</h2><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE html&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">"utf-8"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>网页皮肤<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">section</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">button</span> <span class="attr">id</span>=<span class="string">"pink-btn"</span>&gt;</span>粉色<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">button</span> <span class="attr">id</span>=<span class="string">"green-btn"</span>&gt;</span>绿色<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">button</span> <span class="attr">id</span>=<span class="string">"brown-btn"</span>&gt;</span>卡其<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">section</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">"colorDiv"</span> <span class="attr">style</span>=<span class="string">"width: 500px;height: 500px;border: 1px solid #ccc;background-color: white;"</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">&lt;!-- javascript部分 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span> <span class="attr">type</span>=<span class="string">"text/javascript"</span>&gt;</span><span class="undefined"></span></span><br><span class="line"><span class="javascript">    <span class="comment">//首先检测浏览器是否支持</span></span></span><br><span class="line"><span class="javascript">    <span class="keyword">if</span> (<span class="built_in">window</span>.localStorage) &#123;</span></span><br><span class="line"><span class="javascript">        <span class="built_in">console</span>.log(<span class="string">"浏览器支持localStorage"</span>);</span></span><br><span class="line"><span class="javascript">    &#125; <span class="keyword">else</span> &#123;</span></span><br><span class="line"><span class="javascript">        <span class="built_in">console</span>.log(<span class="string">"浏览器不支持localStorage"</span>);</span></span><br><span class="line"><span class="undefined">    &#125;</span></span><br><span class="line"><span class="undefined"></span></span><br><span class="line"><span class="javascript">    <span class="comment">//事件监听</span></span></span><br><span class="line"><span class="javascript">    <span class="keyword">var</span> EventUtil = &#123;</span></span><br><span class="line"><span class="javascript">        addEvent: <span class="function"><span class="keyword">function</span> (<span class="params">event, type, handler</span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">            <span class="keyword">if</span> (event.addEventListener) &#123;</span></span><br><span class="line"><span class="javascript">                event.addEventListener(type, handler, <span class="literal">false</span>);</span></span><br><span class="line"><span class="javascript">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (event.attachEvent) &#123;</span></span><br><span class="line"><span class="javascript">                event.attachEvent(<span class="string">'on'</span> + type, handler);</span></span><br><span class="line"><span class="javascript">            &#125; <span class="keyword">else</span> &#123;</span></span><br><span class="line"><span class="javascript">                event[<span class="string">'on'</span> + type] = handler;</span></span><br><span class="line"><span class="undefined">            &#125;</span></span><br><span class="line"><span class="undefined">        &#125;</span></span><br><span class="line"><span class="undefined">    &#125;</span></span><br><span class="line"><span class="undefined"></span></span><br><span class="line"><span class="javascript">    <span class="comment">//设置选择样式和保存至localStorage</span></span></span><br><span class="line"><span class="javascript">    <span class="keyword">var</span> colorVal = <span class="string">"white"</span>;</span></span><br><span class="line"><span class="javascript">    <span class="keyword">var</span> colorDiv = <span class="built_in">document</span>.getElementById(<span class="string">"colorDiv"</span>);</span></span><br><span class="line"><span class="javascript">    <span class="keyword">var</span> bgColor = &#123;</span></span><br><span class="line"><span class="javascript">        setColor: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">            colorDiv.style.backgroundColor = <span class="built_in">window</span>.localStorage.bg;</span></span><br><span class="line"><span class="undefined">        &#125;,</span></span><br><span class="line"><span class="undefined"></span></span><br><span class="line"><span class="javascript">        pinkSet: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">            colorVal = <span class="string">"#FFDAB9"</span>;</span></span><br><span class="line"><span class="javascript">            <span class="built_in">window</span>.localStorage.setItem(<span class="string">"bg"</span>, colorVal);</span></span><br><span class="line"><span class="undefined">            bgColor.setColor();</span></span><br><span class="line"><span class="undefined">        &#125;,</span></span><br><span class="line"><span class="undefined"></span></span><br><span class="line"><span class="javascript">        greenSet: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">            colorVal = <span class="string">"#9BCD9B"</span>;</span></span><br><span class="line"><span class="javascript">            <span class="built_in">window</span>.localStorage.setItem(<span class="string">"bg"</span>, colorVal);</span></span><br><span class="line"><span class="undefined">            bgColor.setColor();</span></span><br><span class="line"><span class="undefined">        &#125;,</span></span><br><span class="line"><span class="undefined"></span></span><br><span class="line"><span class="javascript">        brownSet: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">            colorVal = <span class="string">"#CDC9A5"</span>;</span></span><br><span class="line"><span class="javascript">            <span class="built_in">window</span>.localStorage.setItem(<span class="string">"bg"</span>, colorVal);</span></span><br><span class="line"><span class="undefined">            bgColor.setColor();</span></span><br><span class="line"><span class="undefined">        &#125;</span></span><br><span class="line"><span class="undefined">    &#125;</span></span><br><span class="line"><span class="undefined"></span></span><br><span class="line"><span class="undefined"></span></span><br><span class="line"><span class="javascript">    <span class="built_in">window</span>.onload = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span></span><br><span class="line"><span class="undefined">        bgColor.setColor();</span></span><br><span class="line"><span class="javascript">        <span class="keyword">var</span> btnList = <span class="built_in">document</span>.getElementsByTagName(<span class="string">"button"</span>);</span></span><br><span class="line"><span class="javascript">        EventUtil.addEvent(btnList[<span class="number">0</span>], <span class="string">'click'</span>, bgColor.pinkSet);</span></span><br><span class="line"><span class="javascript">        EventUtil.addEvent(btnList[<span class="number">1</span>], <span class="string">'click'</span>, bgColor.greenSet);</span></span><br><span class="line"><span class="javascript">        EventUtil.addEvent(btnList[<span class="number">2</span>], <span class="string">'click'</span>, bgColor.brownSet);</span></span><br><span class="line"><span class="undefined">    &#125;</span></span><br><span class="line"><span class="undefined"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h2 id="7-客户端查看-webStorage"><a href="#7-客户端查看-webStorage" class="headerlink" title="7. 客户端查看 webStorage"></a>7. 客户端查看 webStorage</h2><p><img src="http://xiezixi.oschina.io/blog/images/客户端查看webStorage.png" alt="客户端查看 webStorage"></p>
<h2 id="8-优秀开源框架"><a href="#8-优秀开源框架" class="headerlink" title="8. 优秀开源框架"></a>8. 优秀开源框架</h2><p><a href="https://github.com/marcuswestin/store.js" target="_blank" rel="noopener">store.js</a>，<a href="https://github.com/jaicab/localFont" target="_blank" rel="noopener">localFont</a></p>

          
        
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </div>
  
  
  
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://xiezixi.oschina.io/blog/2018/06/01/HTML5-WebSocket/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="曦瓜皮">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/blog/images/avatar.jpg">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="个人博客">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
                
                <a class="post-title-link" href="/blog/2018/06/01/HTML5-WebSocket/" itemprop="url">HTML5 之 WebSocket™</a></h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2018-06-01T16:42:17+08:00">
                2018-06-01
              </time>
            

            

            
          </span>

          
            <span class="post-category" >
            
              <span class="post-meta-divider">|</span>
            
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              
                <span class="post-meta-item-text">分类于</span>
              
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/blog/categories/HTML5/" itemprop="url" rel="index">
                    <span itemprop="name">HTML5</span>
                  </a>
                </span>

                
                
              
            </span>
          

          
            
          

          
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h2 id="1-WebSocket-简介"><a href="#1-WebSocket-简介" class="headerlink" title="1. WebSocket 简介"></a>1. WebSocket 简介</h2><h3 id="1-1-什么是-WebSocket"><a href="#1-1-什么是-WebSocket" class="headerlink" title="1.1. 什么是 WebSocket"></a>1.1. 什么是 WebSocket</h3><p>WebSocket 是 HTML5 开始提供的一种浏览器与服务器间进行全双工通讯的网络技术，可以传输基于信息的文本和二进制的数据。它于 2011 年被 IETF 定为标准 RFC 6455，同时 WebSocket API 也被 W3C 定为标准。</p>
<p>WebSocket 在连接之后，客户端可以主动发送消息给服务器，服务器也可以主动向客户端推送消息。比如：预订车票信息，除了我们发请求询问车票如何，当然更希望如果有新消息，可以直接通知我们；以及通常见的 web 端实时通讯，实时性的小游戏等等。</p>
<p>其特点：</p>
<ol>
<li>握手阶段采用 HTTP 协议，默认端口是80和443;</li>
<li>建立在 TCP 协议基础之上，和 HTTP 协议同属于应用层;</li>
<li>可以发送文本，也可以发送二进制数据;</li>
<li>没有同源限制，客户端可以与任意服务器通信;</li>
<li>协议标识符是 ws （如果加密，为 wss），如 <code>ws://localhost:8080</code>;</li>
</ol>
<p><img src="http://xiezixi.oschina.io/blog/images/HTTP与WebSocket连接生命周期.png" alt="HTTP 与 WebSocket 连接生命周期"></p>
<h3 id="1-2-为什么用-WebSocket"><a href="#1-2-为什么用-WebSocket" class="headerlink" title="1.2. 为什么用 WebSocket"></a>1.2. 为什么用 WebSocket</h3><p>HTTP 协议有一个缺陷：服务器不能主动联系客户端，只能由客户端发起。它的被动性预示了在完成双向通信时需要不停的连接或连接一直打开，这就需要服务器快速的处理速度或高并发的能力，是非常消耗资源的。</p>
<p>而 WebSocket 的最大特点就是，服务器可以主动向客户端推送信息，客户端也可以主动向服务器发送信息，是真正的双向平等对话，属于服务器推送技术的一种。</p>
<h3 id="1-3-WebSocket-协议的规范"><a href="#1-3-WebSocket-协议的规范" class="headerlink" title="1.3. WebSocket 协议的规范"></a>1.3. WebSocket 协议的规范</h3><p>以下是一个典型的 WebSocket 发起请求到响应请求的示例：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">客户端到服务端：</span><br><span class="line">GET / HTTP/1.1</span><br><span class="line">Connection:Upgrade</span><br><span class="line">Host:127.0.0.1:8088</span><br><span class="line">Origin:null</span><br><span class="line">Sec-WebSocket-Extensions:x-webkit-deflate-frame</span><br><span class="line">Sec-WebSocket-Key:puVOuWb7rel6z2AVZBKnfw==</span><br><span class="line">Sec-WebSocket-Version:13</span><br><span class="line">Upgrade:websocket</span><br><span class="line"></span><br><span class="line">服务端到客户端：</span><br><span class="line">HTTP/1.1 101 Switching Protocols</span><br><span class="line">Connection:Upgrade</span><br><span class="line">Server:beetle websocket server</span><br><span class="line">Upgrade:WebSocket</span><br><span class="line">date: Thu, 10 May 2018 07:32:25 GMT</span><br><span class="line">Access-Control-Allow-Credentials:true</span><br><span class="line">Access-Control-Allow-Headers:content-type</span><br><span class="line">Sec-WebSocket-Accept:FCKgUr8c7OsDsLFeJTWrJw6WO8Q=</span><br></pre></td></tr></table></figure>
<p>我们可以看到，WebSocket 协议和 HTTP 协议乍看并没有太大的区别，但细看下来，区别还是有些的，这其实是一个握手的http请求，首先请求和响应的，<code>Upgrade:WebSocket</code>表示请求的目的就是要将客户端和服务器端的通讯协议从 HTTP 协议升级到 WebSocket协议。从客户端到服务器端请求的信息里包含有<code>Sec-WebSocket-Extensions</code>、<code>Sec-WebSocket-Key</code>这样的头信息。这是客户端浏览器需要向服务器端提供的握手信息，服务器端解析这些头信息，并在握手的过程中依据这些信息生成一个28位的安全密钥并返回给客户端，以表明服务器端获取了客户端的请求，同意创建 WebSocket 连接。</p>
<p>当握手成功后，这个时候 TCP 连接就已经建立了，客户端与服务端就能够直接通过 WebSocket 直接进行数据传递。不过服务端还需要判断一次数据请求是什么时候开始的和什么时候是请求的结束的。在 WebSocket 中，由于浏览端和服务端已经打好招呼，如我发送的内容为 utf-8  编码，如果我发送 0x00,表示包的开始，如果发送了 0xFF，就表示包的结束了。这就解决了黏包的问题。</p>
<h3 id="1-4-浏览器兼容性"><a href="#1-4-浏览器兼容性" class="headerlink" title="1.4. 浏览器兼容性"></a>1.4. 浏览器兼容性</h3><p><a href="https://www.caniuse.com/#search=websocket" target="_blank" rel="noopener">WebSocket 浏览器兼容性</a></p>
<h2 id="2-HTML5-WebSocket-API"><a href="#2-HTML5-WebSocket-API" class="headerlink" title="2. HTML5 WebSocket API"></a>2. HTML5 WebSocket API</h2><p>WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。在 WebSocket API 中，浏览器和服务器只需要做一个握手的动作，然后，浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。</p>
<p>浏览器通过 JavaScript 向服务器发出建立 WebSocket 连接的请求，连接建立以后，客户端和服务器端就可以通过 TCP 连接直接交换数据。当你获取 WebSocket 连接后，你可以通过 <code>send()</code> 方法来向服务器发送数据，并通过 <code>onmessage</code> 事件来接收服务器返回的数据。</p>
<h3 id="2-1-WebSocket-对象"><a href="#2-1-WebSocket-对象" class="headerlink" title="2.1. WebSocket 对象"></a>2.1. WebSocket 对象</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> webSocket = <span class="keyword">new</span> WebSocket(url, [protocol] );</span><br></pre></td></tr></table></figure>
<p>以上代码中的第一个参数 url, 指定连接的 URL。第二个参数 protocol 是可选的，指定了可接受的子协议。</p>
<h3 id="2-2-WebSocket属性"><a href="#2-2-WebSocket属性" class="headerlink" title="2.2. WebSocket属性"></a>2.2. WebSocket属性</h3><p>以下是 WebSocket 对象的属性。假定我们使用了以上代码创建了 webSocket 对象：</p>
<table>
<thead>
<tr>
<th>属性</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td>webSocket.readyState</td>
<td>连接状态</td>
</tr>
<tr>
<td>webSocket.bufferedAmount</td>
<td>只读属性 <code>bufferedAmount</code> 已被 <code>send()</code> 放入正在队列中等待传输，但是还没有发出的 UTF-8 文本字节数</td>
</tr>
</tbody>
</table>
<p>webSocket.readyState：</p>
<ul>
<li>0 表示连接尚未建立</li>
<li>1 表示连接已建立，可以进行通信</li>
<li>2 表示连接正在进行关闭</li>
<li>3 表示连接已经关闭或者连接不能打开</li>
</ul>
<h3 id="2-3-WebSocket-事件"><a href="#2-3-WebSocket-事件" class="headerlink" title="2.3. WebSocket 事件"></a>2.3. WebSocket 事件</h3><p>以下是 WebSocket 对象的相关事件。假定我们使用了以上代码创建了 webSocket 对象：</p>
<table>
<thead>
<tr>
<th>事件</th>
<th>事件处理程序</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td>open</td>
<td>webSocket.onopen</td>
<td>连接建立时触发</td>
</tr>
<tr>
<td>message</td>
<td>webSocket.message</td>
<td>客户端接收服务端数据时触发</td>
</tr>
<tr>
<td>error</td>
<td>webSocket.onerror</td>
<td>通信发生错误时触发</td>
</tr>
<tr>
<td>close</td>
<td>webSocket.onclose</td>
<td>连接关闭时触发</td>
</tr>
</tbody>
</table>
<h3 id="2-4-WebSocket-方法"><a href="#2-4-WebSocket-方法" class="headerlink" title="2.4. WebSocket 方法"></a>2.4. WebSocket 方法</h3><p>以下是 WebSocket 对象的相关方法。假定我们使用了以上代码创建了 webSocket 对象：</p>
<table>
<thead>
<tr>
<th>方法</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td>webSocket.send()</td>
<td>使用连接发送数据</td>
</tr>
<tr>
<td>webSocket.close()</td>
<td>关闭连接</td>
</tr>
</tbody>
</table>
<h2 id="3-客户端实现"><a href="#3-客户端实现" class="headerlink" title="3. 客户端实现"></a>3. 客户端实现</h2><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE html&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">"en"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">"UTF-8"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">name</span>=<span class="string">"viewport"</span> <span class="attr">content</span>=<span class="string">"width=device-width, initial-scale=1.0"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">http-equiv</span>=<span class="string">"X-UA-Compatible"</span> <span class="attr">content</span>=<span class="string">"ie=edge"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>WebSocket 简单实例<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="undefined"></span></span><br><span class="line"><span class="javascript">    <span class="comment">// 创建websocket对象，与websocket官网建立websocket连接</span></span></span><br><span class="line"><span class="javascript">    <span class="keyword">var</span> ws = <span class="keyword">new</span> WebSocket(<span class="string">"wss://echo.websocket.org"</span>);</span></span><br><span class="line"><span class="undefined"></span></span><br><span class="line"><span class="javascript">    <span class="comment">// 建立连接时触发</span></span></span><br><span class="line"><span class="javascript">    ws.onopen = <span class="function"><span class="keyword">function</span> (<span class="params">evt</span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">        <span class="built_in">console</span>.log(<span class="string">"Connection open ..."</span>);</span></span><br><span class="line"><span class="javascript">        <span class="comment">// 向服务端发送数据</span></span></span><br><span class="line"><span class="javascript">        ws.send(<span class="string">"Hello WebSockets!"</span>);</span></span><br><span class="line"><span class="undefined">    &#125;;</span></span><br><span class="line"><span class="undefined"></span></span><br><span class="line"><span class="javascript">    <span class="comment">// 客户端接收服务端数据时触发</span></span></span><br><span class="line"><span class="javascript">    ws.onmessage = <span class="function"><span class="keyword">function</span> (<span class="params">evt</span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">        <span class="built_in">console</span>.log(<span class="string">"Received Message: "</span> + evt.data);</span></span><br><span class="line"><span class="javascript">        <span class="comment">// 关闭连接</span></span></span><br><span class="line"><span class="undefined">        ws.close();</span></span><br><span class="line"><span class="undefined">    &#125;;</span></span><br><span class="line"><span class="undefined"></span></span><br><span class="line"><span class="javascript">    <span class="comment">// 连接关闭时触发</span></span></span><br><span class="line"><span class="javascript">    ws.onclose = <span class="function"><span class="keyword">function</span> (<span class="params">evt</span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">        <span class="built_in">console</span>.log(<span class="string">"Connection closed."</span>);</span></span><br><span class="line"><span class="undefined">    &#125;;</span></span><br><span class="line"><span class="undefined"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p><img src="http://xiezixi.oschina.io/blog/images/webSocket1.png" alt="WebSocket 数据交互信息"></p>
<p><img src="http://xiezixi.oschina.io/blog/images/webSocket2.png" alt="WebSocket 具体连接信息"></p>
<h2 id="4-服务端实现"><a href="#4-服务端实现" class="headerlink" title="4. 服务端实现"></a>4. 服务端实现</h2><p>当然，使用 WebSocket 需要服务端与客户端都提供相应能力，这里基于 Node.js 和 ws 简单建立一个服务端 WebSocket 接口：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> express = <span class="built_in">require</span>(<span class="string">'express'</span>);</span><br><span class="line"><span class="keyword">const</span> WebSocket = <span class="built_in">require</span>(<span class="string">'ws'</span>);</span><br><span class="line"><span class="keyword">const</span> http = <span class="built_in">require</span>(<span class="string">'http'</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> app = express();</span><br><span class="line"></span><br><span class="line">app.get(<span class="string">'/'</span>, <span class="function"><span class="keyword">function</span> (<span class="params">req, res</span>) </span>&#123;</span><br><span class="line">    res.sendfile(<span class="string">'./index.html'</span>);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> server = http.createServer(app);</span><br><span class="line"><span class="keyword">const</span> wss = <span class="keyword">new</span> WebSocket.Server(&#123; server &#125;);</span><br><span class="line"></span><br><span class="line">wss.on(<span class="string">'connection'</span>, <span class="function"><span class="keyword">function</span> <span class="title">connection</span>(<span class="params">ws, req</span>) </span>&#123;</span><br><span class="line">    ws.on(<span class="string">'message'</span>, <span class="function"><span class="keyword">function</span> <span class="title">incoming</span>(<span class="params">message</span>) </span>&#123;</span><br><span class="line">        ws.send(<span class="string">'received: '</span> + message + <span class="string">'(From Server)'</span>);</span><br><span class="line">    &#125;);</span><br><span class="line">    ws.send(<span class="string">'Hello Client'</span>);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">server.listen(<span class="number">8080</span>, <span class="function"><span class="keyword">function</span> <span class="title">listening</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">'Listening on %d'</span>, server.address().port);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>
<h2 id="5-事件与数据"><a href="#5-事件与数据" class="headerlink" title="5. 事件与数据"></a>5. 事件与数据</h2><p>对 WebSocket 实例监听事件有两种方式，这里以 message 事件为例：</p>
<ol>
<li>对 <code>onmessage</code> 属性直接赋值，正如以上：<code>ws.onmessage = function () {};</code>；</li>
<li>使用 <code>addEventListener</code> 监听事件，如：<code>ws.addEventListener(&#39;message&#39;, function () {})</code>；</li>
</ol>
<p>在 message 回调函数中得到 MessageEvent 类型参数 e ，我们需要的数据可以通过 e.data 获取；<br>需要注意的一点是：不论服务端与客户端，其接受到的数据都是序列化后的字符串（当然也有 ArrayBuffer | Blob 类型数据），很多时候我们需要解析处理数据，比如 <code>JSON.parse(e.data)</code>；</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">webSocket.onmessage = <span class="function">(<span class="params">evt</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="comment">// 接受消息</span></span><br><span class="line">  <span class="keyword">let</span> data = &#123;&#125;;</span><br><span class="line">    data = <span class="built_in">JSON</span>.parse(evt.data);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="6-心跳重连"><a href="#6-心跳重连" class="headerlink" title="6. 心跳重连"></a>6. 心跳重连</h2><p>由于网络环境复杂，某些情况会出现断开连接或者连接出错，需要我们在 close 或者 error 事件中监听非正常断开并重连；由于一些原因在 error 时浏览器并不会响应回调事件，因此稳妥的做法还需要在 open 之后开启一个定时任务去判断当前的连接状态 <code>readyState</code> ，在出现异常情况下尝试重连。</p>
<p>webSocket 规范定义了心跳机制，一方可以通过发送 ping（opcode 0x9）消息给另一方，另一方收到 ping 后应该尽可能快的返回 pong（0xA）。</p>
<p>心跳机制是用于检测连接的对方在线状态，因此如果没有心跳，那么无法判断一方还在连接状态中，一些网络层比如 nginx 或者浏览器层会主动断开连接，</p>
<p>在 JavaScript 中，WebSocket 并没有开放 ping/pong 的 API ，虽然浏览器自带了心跳处理，然而不同厂商的实现也不尽相同，因此需要在我们开发时候与服务端约定好一个自实现的心跳机制；</p>
<p>比如浏览器中，检测到 open 事件后，启动一个定时任务，每次发送数据 <code>0x9</code> 给服务端，而服务端返回 <code>0xA</code> 作为响应；</p>
<p>实践下来，心跳的定时任务一般是相隔 15-20 秒发送一次。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// webSocket心跳重连</span></span><br><span class="line"><span class="keyword">const</span> heartCheck = &#123;</span><br><span class="line">  interval: <span class="number">45000</span>, <span class="comment">// 45ms</span></span><br><span class="line">  intervalObj: <span class="literal">null</span>,</span><br><span class="line">  reset() &#123;</span><br><span class="line">    clearInterval(<span class="keyword">this</span>.intervalObj);</span><br><span class="line">    <span class="keyword">this</span>.start();</span><br><span class="line">  &#125;,</span><br><span class="line">  start() &#123;</span><br><span class="line">    <span class="keyword">this</span>.intervalObj = setInterval(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">      webSocket.send(<span class="string">'0x9'</span>);</span><br><span class="line">    &#125;, <span class="keyword">this</span>.interval);</span><br><span class="line">  &#125;,</span><br><span class="line">  remove() &#123;</span><br><span class="line">    clearInterval(<span class="keyword">this</span>.intervalObj);</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// webSocket连接时回调</span></span><br><span class="line">webSocket.onopen = <span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">  heartCheck.start();</span><br><span class="line">&#125;;</span><br><span class="line"><span class="comment">// webSocket断开时回调</span></span><br><span class="line">webSocket.onclose = <span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">  heartCheck.remove();</span><br><span class="line">&#125;;</span><br><span class="line"><span class="comment">// webSocket发生错误时回调</span></span><br><span class="line">webSocket.onerror = <span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">  heartCheck.remove();</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<h2 id="7-WSS"><a href="#7-WSS" class="headerlink" title="7. WSS"></a>7. WSS</h2><p>创建一个 socket 实例时可以选填 ws 和 wss 来进行通信协议的确定。他们两个其实很像 HTTP 和 HTTPS 之间的关系。其中ws表示纯文本通信，而 wss 表示使用加密信道通信（TCP + TLS）。那为啥不直接使用 HTTP 而要自定义通信协议呢？这就要从WebSocket的目的说起来，WebSocket 的主要功能就是为了给浏览器中的应用与服务器端提供优化的，双向的通信机制，但这不代表 WebSocket 只能局限于此，它当然还能够用于其他的场景，这就需要他可以通过非 HTTP 协议来进行数据交换，因此 WebSocket 也就采用了自定义 URI 模式，以确保就算没有 HTTP，也能进行数据交换。</p>
<p>在 HTTP 协议中，很多时候为了加密与安全需要使用 HTTPS 请求（HTTP + TCL）；<br>相应的，在 WebSocket 协议中，也是可以使用加密传输的 —— wss ，比如 <code>wss://localhost:8080</code>。</p>
<p>使用的也是与 HTTPS 一样的证书，在这里一般是交由 Nginx 等服务层去做证书处理。</p>
<h2 id="8-优秀开源框架"><a href="#8-优秀开源框架" class="headerlink" title="8. 优秀开源框架"></a>8. 优秀开源框架</h2><p><a href="https://github.com/socketio/socket.io" target="_blank" rel="noopener">socket.io</a></p>

          
        
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </div>
  
  
  
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://xiezixi.oschina.io/blog/2018/05/16/微信登录/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="曦瓜皮">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/blog/images/avatar.jpg">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="个人博客">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
                
                <a class="post-title-link" href="/blog/2018/05/16/微信登录/" itemprop="url">微信扫码登录</a></h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2018-05-16T09:17:36+08:00">
                2018-05-16
              </time>
            

            

            
          </span>

          
            <span class="post-category" >
            
              <span class="post-meta-divider">|</span>
            
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              
                <span class="post-meta-item-text">分类于</span>
              
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/blog/categories/Wechat/" itemprop="url" rel="index">
                    <span itemprop="name">Wechat</span>
                  </a>
                </span>

                
                
              
            </span>
          

          
            
          

          
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h2 id="微信扫码登录开发指南"><a href="#微信扫码登录开发指南" class="headerlink" title="微信扫码登录开发指南"></a>微信扫码登录开发指南</h2><p>网站应用微信登录是基于OAuth2.0协议标准构建的微信OAuth2.0授权登录系统。</p>
<h3 id="授权流程说明"><a href="#授权流程说明" class="headerlink" title="授权流程说明"></a>授权流程说明</h3><p>微信OAuth2.0授权登录让微信用户使用微信身份安全登录第三方应用或网站，在微信用户授权登录已接入微信OAuth2.0的第三方应用后，第三方可以获取到用户的接口调用凭证（access_token），通过access_token可以进行微信开放平台授权关系接口调用，从而可实现获取微信用户基本开放信息和帮助用户实现基础开放功能等。</p>
<h3 id="授权整体流程"><a href="#授权整体流程" class="headerlink" title="授权整体流程"></a>授权整体流程</h3><blockquote>
<ol>
<li>第三方发起微信授权登录请求，微信用户允许授权第三方应用后，微信会拉起应用或重定向到第三方网站，并且带上授权临时票据code参数；</li>
<li>通过code参数加上AppID和AppSecret等，通过API换取access_token；</li>
<li>通过access_token进行接口调用，获取用户基本数据资源或帮助用户实现基本操作。</li>
</ol>
</blockquote>
<h3 id="获取access-token时序图"><a href="#获取access-token时序图" class="headerlink" title="获取access_token时序图"></a>获取access_token时序图</h3><p><img src="http://xiezixi.oschina.io/blog/images/获取access_token时序图.png" alt="获取access_token时序图"></p>
<h2 id="微信扫码登录方式及区别"><a href="#微信扫码登录方式及区别" class="headerlink" title="微信扫码登录方式及区别"></a>微信扫码登录方式及区别</h2><h3 id="平台分类"><a href="#平台分类" class="headerlink" title="平台分类"></a>平台分类</h3><blockquote>
<ul>
<li><a href="https://open.weixin.qq.com/" target="_blank" rel="noopener">微信开放平台</a></li>
<li><a href="https://mp.weixin.qq.com/" target="_blank" rel="noopener">微信公众平台</a></li>
</ul>
</blockquote>
<h3 id="扫码登录API"><a href="#扫码登录API" class="headerlink" title="扫码登录API"></a>扫码登录API</h3><blockquote>
<ul>
<li><a href="https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&amp;t=resource/res_list&amp;verify=1&amp;id=open1419316505&amp;token=&amp;lang=zh_CN" target="_blank" rel="noopener">微信开放平台扫码登录</a></li>
<li><a href="https://mp.weixin.qq.com/wiki?t=resource/res_main&amp;id=mp1421140842" target="_blank" rel="noopener">微信公众平台扫码登录</a></li>
</ul>
</blockquote>
<h3 id="两者区别与联系"><a href="#两者区别与联系" class="headerlink" title="两者区别与联系"></a>两者区别与联系</h3><blockquote>
<ol>
<li>两者都可以通过微信客户端扫码授权的方式，让第三方页面获得微信用户的一些基本信息（昵称、性别、所在地、在微信唯一标示等……）。两者都是通过提供一个链接让用户授权的方式。但网页版需要在页面打开二维码之后授权，而公众号则需要用户先关注公众号，然后点开公众号里面的链接，确认授权即可;</li>
<li>网页扫码登录需要将授权的链接（二维码链接）在网页中打开、而公众号授权登录的链接必须要微信客户端中打开;</li>
<li>无论网页扫码登录还是在公众号中授权登录，都是通过授权的方式获得一个code参数，之后通过code参数获取access_token和openid和通过access_token和openid去获取用户的基本信息，接口请求链接是一样的</li>
<li>微信公众平台提供测试号，但开放平台需要花钱注册。</li>
</ol>
</blockquote>
<h2 id="公众号扫码登录Demo"><a href="#公众号扫码登录Demo" class="headerlink" title="公众号扫码登录Demo"></a>公众号扫码登录Demo</h2><h3 id="生成在线二维码"><a href="#生成在线二维码" class="headerlink" title="生成在线二维码"></a>生成在线二维码</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxc2534e9ca299601d&amp;redirect_uri=http%3A%2F%2Fxiezixi.tunnel.echomod.cn%2Fwechat%2Flogin&amp;response_type=code&amp;scope=snsapi_userinfo&amp;state=11#wechat_redirect</span><br></pre></td></tr></table></figure>
<h3 id="AuthUtil"><a href="#AuthUtil" class="headerlink" title="AuthUtil"></a>AuthUtil</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.xzx.wechatLogin.wechat.util;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.alibaba.fastjson.JSON;</span><br><span class="line"><span class="keyword">import</span> com.alibaba.fastjson.JSONObject;</span><br><span class="line"><span class="keyword">import</span> org.apache.http.client.fluent.Request;</span><br><span class="line"><span class="keyword">import</span> org.apache.http.client.utils.URIBuilder;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.net.URISyntaxException;</span><br><span class="line"><span class="keyword">import</span> java.nio.charset.Charset;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">AuthUtil</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> String APP_ID = <span class="string">"wxc2534e9ca299601d"</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> String APP_SECRET = <span class="string">"c3489bf8d1325ec8b271b243bb09198b"</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> String GRANT_TYPE = <span class="string">"authorization_code"</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 通过code获取access_token</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> code</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     * <span class="doctag">@throws</span> IOException</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@throws</span> URISyntaxException</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> JSONObject <span class="title">getAccessToken</span><span class="params">(String code)</span> <span class="keyword">throws</span> IOException, URISyntaxException </span>&#123;</span><br><span class="line">        URIBuilder uriBuilder = <span class="keyword">new</span> URIBuilder()</span><br><span class="line">                .setScheme(<span class="string">"https"</span>)</span><br><span class="line">                .setHost(<span class="string">"api.weixin.qq.com"</span>)</span><br><span class="line">                .setPath(<span class="string">"/sns/oauth2/access_token"</span>)</span><br><span class="line">                .addParameter(<span class="string">"appid"</span>, APP_ID)</span><br><span class="line">                .addParameter(<span class="string">"secret"</span>,APP_SECRET)</span><br><span class="line">                .addParameter(<span class="string">"code"</span>,code)</span><br><span class="line">                .addParameter(<span class="string">"grant_type"</span>,GRANT_TYPE);</span><br><span class="line">        String content = Request.Get(uriBuilder.build()).connectTimeout(<span class="number">10000</span>)</span><br><span class="line">                .execute().returnContent().asString(Charset.defaultCharset());</span><br><span class="line">        <span class="keyword">return</span> JSON.parseObject(content);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 通过access_token和open_id获取用户基本信息</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> accessToken</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> openId</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     * <span class="doctag">@throws</span> IOException</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@throws</span> URISyntaxException</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> JSONObject <span class="title">getUserInfo</span><span class="params">(String accessToken,String openId)</span> <span class="keyword">throws</span> IOException, URISyntaxException </span>&#123;</span><br><span class="line">        URIBuilder uriBuilder = <span class="keyword">new</span> URIBuilder()</span><br><span class="line">                .setScheme(<span class="string">"https"</span>)</span><br><span class="line">                .setHost(<span class="string">"api.weixin.qq.com"</span>)</span><br><span class="line">                .setPath(<span class="string">"/sns/userinfo"</span>)</span><br><span class="line">                .addParameter(<span class="string">"access_token"</span>, accessToken)</span><br><span class="line">                .addParameter(<span class="string">"openid"</span>, openId);</span><br><span class="line">        <span class="comment">// GET</span></span><br><span class="line">        String content = Request.Get(uriBuilder.build()).connectTimeout(<span class="number">10000</span>)</span><br><span class="line">                .execute().returnContent().asString(Charset.defaultCharset());</span><br><span class="line">        <span class="keyword">return</span> JSON.parseObject(content);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="LoginController"><a href="#LoginController" class="headerlink" title="LoginController"></a>LoginController</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.xzx.wechatLogin.wechat.controller;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.alibaba.fastjson.JSONObject;</span><br><span class="line"><span class="keyword">import</span> com.xzx.wechatLogin.wechat.util.AuthUtil;</span><br><span class="line"><span class="keyword">import</span> org.slf4j.Logger;</span><br><span class="line"><span class="keyword">import</span> org.slf4j.LoggerFactory;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.GetMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RequestMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RequestParam;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RestController;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.net.URISyntaxException;</span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;</span><br><span class="line"></span><br><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@RequestMapping</span>(<span class="string">"/wechat"</span>)</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">LoginController</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> Logger log = LoggerFactory.getLogger(LoginController.class);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> HashMap&lt;String,String&gt; userMap = <span class="keyword">new</span> HashMap&lt;&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="meta">@GetMapping</span>(<span class="string">"/binding"</span>)</span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">binding</span><span class="params">(@RequestParam String code, @RequestParam String state)</span> <span class="keyword">throws</span> IOException, URISyntaxException </span>&#123;</span><br><span class="line">        JSONObject accessToken = AuthUtil.getAccessToken(code);</span><br><span class="line">        log.info(<span class="string">"userId: &#123;&#125; , open_id: &#123;&#125;"</span>, state,accessToken.getString(<span class="string">"openid"</span>));</span><br><span class="line">        userMap.put(accessToken.getString(<span class="string">"openid"</span>),state);</span><br><span class="line">        <span class="keyword">return</span> <span class="string">"绑定成功"</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@GetMapping</span>(<span class="string">"/login"</span>)</span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">login</span><span class="params">(@RequestParam String code, @RequestParam String state)</span> <span class="keyword">throws</span> IOException, URISyntaxException </span>&#123;</span><br><span class="line">        JSONObject accessToken = AuthUtil.getAccessToken(code);</span><br><span class="line">        log.info(<span class="string">"open_id: &#123;&#125;"</span>, state,accessToken.getString(<span class="string">"openid"</span>));</span><br><span class="line">        <span class="keyword">if</span> (userMap.get(accessToken.getString(<span class="string">"openid"</span>)) == <span class="keyword">null</span>)&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="string">"请先注册，再绑定微信"</span>;</span><br><span class="line">        &#125;<span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="string">"已绑定，登录成功"</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
          
        
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </div>
  
  
  
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://xiezixi.oschina.io/blog/2018/05/15/linux基本命令/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="曦瓜皮">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/blog/images/avatar.jpg">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="个人博客">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
                
                <a class="post-title-link" href="/blog/2018/05/15/linux基本命令/" itemprop="url">Linux基本命令</a></h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2018-05-15T19:52:50+08:00">
                2018-05-15
              </time>
            

            

            
          </span>

          
            <span class="post-category" >
            
              <span class="post-meta-divider">|</span>
            
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              
                <span class="post-meta-item-text">分类于</span>
              
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/blog/categories/Linux/" itemprop="url" rel="index">
                    <span itemprop="name">Linux</span>
                  </a>
                </span>

                
                
              
            </span>
          

          
            
          

          
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h2 id="帮助命令"><a href="#帮助命令" class="headerlink" title="帮助命令"></a>帮助命令</h2><blockquote>
<ol>
<li><strong>whatis</strong>      <em>简要的说明命令</em></li>
<li><strong>info</strong>        <em>详细的说明命令</em></li>
<li><strong>man</strong>         <em>查询命令的说明文档</em></li>
<li><strong>which</strong>       <em>查询程序binary文件所在的目录</em></li>
<li><strong>whereis</strong>     <em>查询程序的搜索路径</em></li>
</ol>
</blockquote>
<p>在linux终端，面对命令不知道怎么用，或不记得命令的拼写及参数时，我们需要求助于系统的帮助文档； linux系统内置的帮助文档很详细，通常能解决我们的问题，我们需要掌握如何正确的去使用它们；</p>
<blockquote>
<ul>
<li>在只记得部分命令关键字的场合，我们可通过man -k来搜索；</li>
<li>需要知道某个命令的简要说明，可以使用whatis；而更详细的介绍，则可用info命令；</li>
<li>查看命令在哪个位置，我们需要使用which；</li>
<li>而对于命令的具体参数及使用方法，我们需要用到强大的man。</li>
</ul>
</blockquote>
<h3 id="查询命令"><a href="#查询命令" class="headerlink" title="查询命令"></a>查询命令</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">whatis <span class="built_in">command</span>    <span class="comment"># 查询命令的简要说明</span></span><br><span class="line">info <span class="built_in">command</span>      <span class="comment"># 查询命令的详细说明</span></span><br><span class="line">man <span class="built_in">command</span>       <span class="comment"># 查询命令的说明文档</span></span><br></pre></td></tr></table></figure>
<h3 id="查看路径"><a href="#查看路径" class="headerlink" title="查看路径"></a>查看路径</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">which</span> <span class="built_in">command</span>     <span class="comment"># 查看程序的binary文件所在路径</span></span><br><span class="line">whereis <span class="built_in">command</span>   <span class="comment"># 查看程序的搜索路径</span></span><br></pre></td></tr></table></figure>
<h2 id="文件及目录管理"><a href="#文件及目录管理" class="headerlink" title="文件及目录管理"></a>文件及目录管理</h2><blockquote>
<ol>
<li><strong>mkdir</strong>                  <em>创建目录</em></li>
<li><strong>rm</strong>                     <em>删除</em></li>
<li><strong>mv</strong>                     <em>移动或更名文件</em></li>
<li><strong>cp</strong>                     <em>复制文件</em></li>
<li><strong>cd</strong>                     <em>目录切换</em></li>
<li><strong>pwd</strong>                    <em>显示当前路径</em></li>
<li><strong>ls</strong>                     <em>列出目录项</em></li>
<li><strong>find/locate</strong>            <em>查找目录或文件</em></li>
<li><strong>updatedb</strong>               <em>更新索引库</em></li>
<li><strong>cat/vi/head/tail/more</strong> <em>查看文件内容</em></li>
<li><strong>diff</strong>                  <em>查看两个文件间的差别</em></li>
<li><strong>egrep/grep</strong>            <em>查找文件内容</em></li>
<li><strong>chown</strong>                 <em>修改文件拥有者</em></li>
<li><strong>chmod</strong>                 <em>修改文件权限</em></li>
<li><strong>ln</strong>                    <em>增加别名</em></li>
<li><strong>|</strong>                     <em>批处理命令连接执行</em></li>
<li><strong>;</strong>                     <em>串联</em></li>
<li><strong>&amp;&amp;</strong>                    <em>前面成功，则执行后面一条，否则，不执行</em></li>
<li><strong>||</strong>                    <em>前面失败，则后一条执行</em></li>
<li><strong>.profile</strong>              <em>设置环境变量</em></li>
</ol>
</blockquote>
<p>文件管理不外乎文件或目录的创建、删除、查询、移动，有mkdir/rm/mv；文件查询是重点，用find来进行查询；find的参数丰富，也非常强大；有时候，需要给文件创建一个别名，我们需要用到ln，使用这个别名和使用原文件是相同的效果。</p>
<h3 id="创建、删除、查询、移动"><a href="#创建、删除、查询、移动" class="headerlink" title="创建、删除、查询、移动"></a>创建、删除、查询、移动</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">mkdir       <span class="comment"># 创建目录</span></span><br><span class="line">rm          <span class="comment"># 删除文件或目录(-rf 删除非空目录)</span></span><br><span class="line">mv          <span class="comment"># 移动/重命名文件</span></span><br><span class="line">cp          <span class="comment"># 复制</span></span><br><span class="line">find        <span class="comment"># 查询</span></span><br></pre></td></tr></table></figure>
<h3 id="目录切换"><a href="#目录切换" class="headerlink" title="目录切换"></a>目录切换</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span>          <span class="comment"># 找到文件/目录位置</span></span><br><span class="line"><span class="built_in">cd</span> -        <span class="comment"># 切换到上一个工作目录</span></span><br><span class="line"><span class="built_in">cd</span> or <span class="built_in">cd</span> ~  <span class="comment"># 切换到home目录</span></span><br><span class="line"><span class="built_in">pwd</span>         <span class="comment"># 显示当前路径</span></span><br></pre></td></tr></table></figure>
<h3 id="列出目录项"><a href="#列出目录项" class="headerlink" title="列出目录项"></a>列出目录项</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">ls          <span class="comment"># 显示当前目录下的文件，目录</span></span><br><span class="line">ls -lrt     <span class="comment"># 按时间排序，列表的形式显示目录项</span></span><br><span class="line">ls | cat -n <span class="comment"># 给文件添加id编号</span></span><br><span class="line">ls -al | more   <span class="comment"># 按页显示列表内容</span></span><br></pre></td></tr></table></figure>
<p>在.bashrc 中设置命令别名，.bashrc 在/home/你的用户名/ 文件夹下，以隐藏文件的方式存储；可使用 ls -a 查看。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">alias</span> lsl=<span class="string">'ls -lrt'</span></span><br><span class="line"><span class="built_in">alias</span> lm=<span class="string">'ls -al|more'</span></span><br></pre></td></tr></table></figure>
<h3 id="查找目录及文件"><a href="#查找目录及文件" class="headerlink" title="查找目录及文件"></a>查找目录及文件</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">find ./ -name <span class="string">"tomcat*"</span> | xargs file    <span class="comment"># 查询文件或目录</span></span><br><span class="line">find ./ -name <span class="string">'*.txt'</span>                   <span class="comment"># 查询是否含有txt文件</span></span><br><span class="line">locate string                           <span class="comment"># 查询所有包含string的路径</span></span><br></pre></td></tr></table></figure>
<p>find是实时查找，如果需要更快的查询，可试试locate；locate会为文件系统建立索引数据库，如果有文件更新，需要定期执行更新命令来更新索引库:</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">updatedb</span><br></pre></td></tr></table></figure>
<h3 id="查看文件内容"><a href="#查看文件内容" class="headerlink" title="查看文件内容"></a>查看文件内容</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">cat -n file         <span class="comment"># 显示时同时显示行号</span></span><br><span class="line">head -10 file       <span class="comment"># 显示前10行</span></span><br><span class="line">tail -10 file       <span class="comment"># 显示后10行</span></span><br><span class="line">diff file1 file2    <span class="comment"># 查看两个文件的差别</span></span><br><span class="line">tail -f file        <span class="comment"># 动态显示文本最新信息(查看日志信息)</span></span><br></pre></td></tr></table></figure>
<h3 id="查找文件内容"><a href="#查找文件内容" class="headerlink" title="查找文件内容"></a>查找文件内容</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">egrep <span class="string">'03.1\/CO\/AE'</span> TSF_STAT_111130.log.012</span><br><span class="line">egrep <span class="string">'A_LMCA777:C'</span> TSF_STAT_111130.log.035 &gt; co.out2</span><br></pre></td></tr></table></figure>
<h3 id="修改文件与目录权限"><a href="#修改文件与目录权限" class="headerlink" title="*修改文件与目录权限"></a>*修改文件与目录权限</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">chown                       <span class="comment"># 改变文件的拥有者</span></span><br><span class="line">chmod                       <span class="comment"># 改变文件读、写、执行等属性</span></span><br><span class="line">chown -R tuxapp <span class="built_in">source</span>/     <span class="comment"># 递归子目录修改</span></span><br><span class="line">chmod a+x myscript          <span class="comment"># 增加脚本可执行权限</span></span><br></pre></td></tr></table></figure>
<h3 id="给文件增加别名"><a href="#给文件增加别名" class="headerlink" title="给文件增加别名"></a>给文件增加别名</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">ln cc ccAgain   <span class="comment"># 硬连接；删除一个，将仍能找到；</span></span><br><span class="line">ln -s cc ccTo   <span class="comment"># 符号链接(软链接)；删除源，另一个无法使用；（后面一个ccTo 为新建的文件）</span></span><br></pre></td></tr></table></figure>
<h3 id="管道和重定向"><a href="#管道和重定向" class="headerlink" title="管道和重定向"></a>管道和重定向</h3><blockquote>
<ul>
<li>批处理命令连接执行，使用 |</li>
<li>串联: 使用分号 ;</li>
<li>前面成功，则执行后面一条，否则，不执行：&amp;&amp;</li>
<li>前面失败，则后一条执行: ||</li>
</ul>
</blockquote>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">ls /proc &amp;&amp; <span class="built_in">echo</span>  suss! || <span class="built_in">echo</span> failed.         <span class="comment"># 能够提示命名是否执行成功or失败</span></span><br><span class="line"><span class="keyword">if</span> ls /proc; <span class="keyword">then</span> <span class="built_in">echo</span> suss; <span class="keyword">else</span> <span class="built_in">echo</span> fail; <span class="keyword">fi</span> <span class="comment"># 与上述效果相同</span></span><br><span class="line">:&gt; a.txt                                        <span class="comment"># 清空文件</span></span><br><span class="line"><span class="built_in">echo</span> aa &gt;&gt; a.txt                                <span class="comment"># 重定向</span></span><br></pre></td></tr></table></figure>
<h3 id="设置环境变量"><a href="#设置环境变量" class="headerlink" title="设置环境变量"></a>设置环境变量</h3><p>启动帐号后自动执行的是 文件为 .profile，然后通过这个文件可设置自己的环境变量；<br>安装的软件路径一般需要加入到path中：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">PATH=<span class="variable">$APPDIR</span>:/opt/app/soft/bin:<span class="variable">$PATH</span>:/usr/<span class="built_in">local</span>/bin:<span class="variable">$TUXDIR</span>/bin:<span class="variable">$ORACLE_HOME</span>/bin;<span class="built_in">export</span> PATH</span><br></pre></td></tr></table></figure>
<h3 id="Bash快捷输入或删除"><a href="#Bash快捷输入或删除" class="headerlink" title="Bash快捷输入或删除"></a>Bash快捷输入或删除</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">Ctl-U   删除光标到行首的所有字符,在某些设置下,删除全行</span><br><span class="line">Ctl-W   删除当前光标到前边的最近一个空格之间的字符</span><br><span class="line">Ctl-H   backspace,删除光标前边的字符</span><br><span class="line">Ctl-R   匹配最相近的一个文件，然后输出</span><br></pre></td></tr></table></figure>
<h3 id="综合应用"><a href="#综合应用" class="headerlink" title="综合应用"></a>综合应用</h3><p>查找record.log中包含AAA，但不包含BBB的记录的总数:</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">cat -v record.log | grep AAA | grep -v BBB | wc -l</span><br></pre></td></tr></table></figure>
<h2 id="网络工具"><a href="#网络工具" class="headerlink" title="网络工具"></a>网络工具</h2><h3 id="查询网络服务和端口"><a href="#查询网络服务和端口" class="headerlink" title="查询网络服务和端口"></a>查询网络服务和端口</h3><h2 id="用户管理工具"><a href="#用户管理工具" class="headerlink" title="用户管理工具"></a>用户管理工具</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">useradd                 <span class="comment"># 添加用户</span></span><br><span class="line">passwd                  <span class="comment"># 为用户设置密码</span></span><br><span class="line">userdel                 <span class="comment"># 删除用户</span></span><br><span class="line">su                      <span class="comment"># 账号切换</span></span><br><span class="line">groups                  <span class="comment"># 查看当前用户所属的组</span></span><br><span class="line">usermod                 <span class="comment"># 修改用户所属的组</span></span><br><span class="line">chmod                   <span class="comment"># 更改读写权限</span></span><br><span class="line">chown                   <span class="comment"># 更改文件或目录的拥有者</span></span><br><span class="line">.bashrc/.bash_profile   <span class="comment"># 环境变量</span></span><br></pre></td></tr></table></figure>
<h3 id="用户"><a href="#用户" class="headerlink" title="用户"></a>用户</h3><h4 id="添加用户"><a href="#添加用户" class="headerlink" title="添加用户"></a>添加用户</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">useradd -m username         <span class="comment"># 该命令为用户创建相应的帐号和用户目录/home/username</span></span><br><span class="line">passwd username             <span class="comment"># 密码以交互方式创建</span></span><br></pre></td></tr></table></figure>
<h4 id="删除用户"><a href="#删除用户" class="headerlink" title="删除用户"></a>删除用户</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">userdel -r username         <span class="comment"># 删除用户</span></span><br><span class="line">su userB                    <span class="comment"># 帐号切换</span></span><br></pre></td></tr></table></figure>
<h3 id="用户的组"><a href="#用户的组" class="headerlink" title="用户的组"></a>用户的组</h3><h4 id="将用户加入到组"><a href="#将用户加入到组" class="headerlink" title="将用户加入到组"></a>将用户加入到组</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">groups                          <span class="comment"># 查看当前用户所属的组</span></span><br><span class="line">usermod -G groupNmame username  <span class="comment"># 将用户加入到组</span></span><br><span class="line">usermod -g groupName username   <span class="comment"># 变更用户所属的组</span></span><br></pre></td></tr></table></figure>
<h4 id="查看系统所有的组"><a href="#查看系统所有的组" class="headerlink" title="查看系统所有的组"></a>查看系统所有的组</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">more /etc/passwd        <span class="comment"># 查看所有用户及权限</span></span><br><span class="line">more /etc/group         <span class="comment"># 查看所有的用户组及权限</span></span><br></pre></td></tr></table></figure>
<h3 id="用户权限"><a href="#用户权限" class="headerlink" title="用户权限"></a>用户权限</h3><h4 id="更改读写权限"><a href="#更改读写权限" class="headerlink" title="更改读写权限"></a>更改读写权限</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">chmod userMark(+|-)PermissionsMark  <span class="comment"># 更改读写权限</span></span><br><span class="line"><span class="comment"># userMark取值：(u：用户，g：组，o：其它用户，a：所有用户)</span></span><br><span class="line"><span class="comment"># PermissionsMark取值：(r:读，w：写，x：执行)</span></span><br><span class="line"><span class="comment"># 例如：</span></span><br><span class="line">chmod a+x main      <span class="comment"># 对所有用户给文件main增加可执行权限</span></span><br><span class="line">chmod g+w blogs     <span class="comment"># 对组用户给文件blogs增加可写权限</span></span><br></pre></td></tr></table></figure>
<h4 id="更改文件或目录的拥有者"><a href="#更改文件或目录的拥有者" class="headerlink" title="更改文件或目录的拥有者"></a>更改文件或目录的拥有者</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">chown username dirOrFile    <span class="comment"># 更改文件或目录的拥有者</span></span><br></pre></td></tr></table></figure>
<h3 id="环境变量"><a href="#环境变量" class="headerlink" title="环境变量"></a>环境变量</h3><p>/etc/profile，/etc/bashrc 是系统全局环境变量设定<br>~/.profile，~/.bashrc用户目录下的私有环境变量设定</p>
<h2 id="系统管理及IPC资源管理"><a href="#系统管理及IPC资源管理" class="headerlink" title="系统管理及IPC资源管理"></a>系统管理及IPC资源管理</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 汇总</span></span><br><span class="line">uname/lsb_release       <span class="comment"># 查看Linux系统版本(Linux Standard Base)</span></span><br><span class="line">sar                     <span class="comment"># 查看(System Activity Reporter)</span></span><br><span class="line">arch                    <span class="comment"># 显示架构(Autoregressive conditional heteroskedasticity model)</span></span><br><span class="line">date                    <span class="comment"># 查看设置系统时间</span></span><br><span class="line">clock                   <span class="comment"># 强制把系统时间写入CMOS</span></span><br><span class="line">tzselect                <span class="comment"># 选择时区</span></span><br><span class="line">ipcs                    <span class="comment"># IPC资源查询(Inter-Process Communication)</span></span><br><span class="line"><span class="built_in">ulimit</span>                  <span class="comment"># 检测和设置系统资源限制</span></span><br></pre></td></tr></table></figure>
<h3 id="系统管理"><a href="#系统管理" class="headerlink" title="系统管理"></a>系统管理</h3><h4 id="查询系统版本"><a href="#查询系统版本" class="headerlink" title="查询系统版本"></a>查询系统版本</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">uname -a            <span class="comment"># 查看Linux系统版本</span></span><br><span class="line">lsb_release -a      <span class="comment"># 查看Linux系统版本</span></span><br><span class="line">more /etc/release   <span class="comment"># 查看Unix系统版本</span></span><br></pre></td></tr></table></figure>
<h4 id="查询硬件信息"><a href="#查询硬件信息" class="headerlink" title="查询硬件信息"></a>查询硬件信息</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">sar -u 5 10                                 <span class="comment"># 查看CPU使用情况</span></span><br><span class="line">cat /proc/cpuinfo                           <span class="comment"># 查询CPU信息</span></span><br><span class="line">cat /proc/cpuinfo | grep processor | wc -l  <span class="comment"># 查看CPU的核的个数</span></span><br><span class="line">cat /proc/meminfo                           <span class="comment"># 查看内存信息</span></span><br><span class="line">pagesize                                    <span class="comment"># 显示内存page大小（以KByte为单位）</span></span><br><span class="line">arch                                        <span class="comment"># 显示架构</span></span><br></pre></td></tr></table></figure>
<h4 id="设置系统时间"><a href="#设置系统时间" class="headerlink" title="设置系统时间"></a>设置系统时间</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">date                            <span class="comment"># 显示当前系统时间</span></span><br><span class="line">date -s 2014-09-15 17:05:00     <span class="comment"># 设置系统日期和时间</span></span><br><span class="line">tzselect                        <span class="comment"># 设置时区</span></span><br><span class="line">clock -w                        <span class="comment"># 强制把系统时间写入CMOS</span></span><br><span class="line">date +%Y%m%d.%H%M%S             <span class="comment"># 格式化输出当前日期时间</span></span><br></pre></td></tr></table></figure>
<h3 id="IPC资源管理"><a href="#IPC资源管理" class="headerlink" title="IPC资源管理"></a>IPC资源管理</h3><h4 id="IPC资源查询"><a href="#IPC资源查询" class="headerlink" title="IPC资源查询"></a>IPC资源查询</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">ipcs                    <span class="comment"># 查看系统使用的IPC资源</span></span><br><span class="line"><span class="built_in">ulimit</span>                  <span class="comment"># 检测和设置系统资源限制</span></span><br><span class="line"><span class="built_in">ulimit</span> –c unlimited     <span class="comment"># 对生成的 core 文件的大小不进行限制</span></span><br></pre></td></tr></table></figure>

          
        
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </div>
  
  
  
  </article>


    
  </section>

  
  <nav class="pagination">
    <a class="extend prev" rel="prev" href="/blog/"><i class="fa fa-angle-left"></i></a><a class="page-number" href="/blog/">1</a><span class="page-number current">2</span>
  </nav>



          </div>
          


          

        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    
    <div class="sidebar-inner">

      

      

      <section class="site-overview sidebar-panel sidebar-panel-active">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
          <img class="site-author-image" itemprop="image"
               src="/blog/images/avatar.jpg"
               alt="曦瓜皮" />
          <p class="site-author-name" itemprop="name">曦瓜皮</p>
           
              <p class="site-description motion-element" itemprop="description"></p>
          
        </div>
        <nav class="site-state motion-element">

          
            <div class="site-state-item site-state-posts">
              <a href="/blog/archives/">
                <span class="site-state-item-count">15</span>
                <span class="site-state-item-name">日志</span>
              </a>
            </div>
          

          
            
            
            <div class="site-state-item site-state-categories">
              <a href="/blog/categories/index.html">
                <span class="site-state-item-count">6</span>
                <span class="site-state-item-name">分类</span>
              </a>
            </div>
          

          

        </nav>

        

        <div class="links-of-author motion-element">
          
        </div>

        
        

        
        

        

      </section>

      

      

    </div>
  </aside>


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright" >
  
  &copy; 
  <span itemprop="copyrightYear">2018</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">曦瓜皮</span>
</div>


<div class="powered-by">
  由 <a class="theme-link" href="https://hexo.io">Hexo</a> 强力驱动
</div>

<div class="theme-info">
  主题 -
  <a class="theme-link" href="https://github.com/iissnan/hexo-theme-next">
    NexT.Muse
  </a>
</div>


        

        
      </div>
    </footer>

    
      <div class="back-to-top">
        <i class="fa fa-arrow-up"></i>
        
      </div>
    

  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>









  












  
  <script type="text/javascript" src="/blog/lib/jquery/index.js?v=2.1.3"></script>

  
  <script type="text/javascript" src="/blog/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script>

  
  <script type="text/javascript" src="/blog/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>

  
  <script type="text/javascript" src="/blog/lib/velocity/velocity.min.js?v=1.2.1"></script>

  
  <script type="text/javascript" src="/blog/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>

  
  <script type="text/javascript" src="/blog/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script>


  


  <script type="text/javascript" src="/blog/js/src/utils.js?v=5.1.2"></script>

  <script type="text/javascript" src="/blog/js/src/motion.js?v=5.1.2"></script>



  
  

  
    <script type="text/javascript" src="/blog/js/src/scrollspy.js?v=5.1.2"></script>
<script type="text/javascript" src="/blog/js/src/post-details.js?v=5.1.2"></script>

  

  


  <script type="text/javascript" src="/blog/js/src/bootstrap.js?v=5.1.2"></script>



  


  




	





  





  






  





  

  

  

  

  

  

</body>
</html>
